package simpledb.transaction;

import simpledb.common.Database;

import java.io.IOException;

/**
 * Transaction 类封装了一个事务的状态信息，并负责管理事务的提交（commit）和回滚（abort）。
 *
 * 每个事务都有一个唯一的事务 ID（TransactionId），用于标识该事务。
 */
public class Transaction {

    private final TransactionId tid;            // 当前事务的唯一标识符
    volatile boolean            started = false; // 标记事务是否已开始运行

    /**
     * 构造一个新的事务对象，为其分配一个唯一的事务 ID。
     */
    public Transaction() {
        tid = new TransactionId();
    }

    /**
     * 启动事务。
     * 记录事务的开始日志到日志文件中。
     */
    public void start() {
        started = true;
        try {
            Database.getLogFile().logXactionBegin(tid); // 写入事务开始日志记录
        } catch (IOException e) {
            e.printStackTrace(); // 日志写入失败时打印异常信息
        }
    }

    /**
     * 获取当前事务的唯一标识符。
     *
     * @return 当前事务的 TransactionId 对象
     */
    public TransactionId getId() {
        return tid;
    }

    /**
     * 提交事务。
     *
     * @throws IOException 如果在提交过程中发生 I/O 错误
     */
    public void commit() throws IOException {
        transactionComplete(false); // false 表示正常提交
    }

    /**
     * 回滚事务。
     *
     * @throws IOException 如果在回滚过程中发生 I/O 错误
     */
    public void abort() throws IOException {
        transactionComplete(true); // true 表示回滚
    }

    /**
     * 处理事务的完成操作（提交或回滚）
     *
     * @param abort 是否为回滚操作
     * @throws IOException 如果日志操作或缓冲池清理失败
     */
    public void transactionComplete(boolean abort) throws IOException {

        if (started) {
            // 如果是回滚操作，先记录回滚日志并执行回滚
            if (abort) {
                Database.getLogFile().logAbort(tid); // 包括回滚操作的日志记录
            }

            // 释放该事务持有的所有锁，并根据需要刷新缓冲池中的页
            Database.getBufferPool().transactionComplete(tid, !abort); // 释放锁

            // 如果是提交操作，记录提交日志
            if (!abort) {
                Database.getLogFile().logCommit(tid);
            }

            // 标记事务已完成（可以重复调用，不影响）
            started = false;
        }
    }
}
